package com.example.shopping.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.example.shopping.mapper.OrderMapper;
import com.example.shopping.model.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;

    public void createOrder() {
        log.info("开始执行");
        for (int i = 0; i < 1000; i++) {
            long id = System.currentTimeMillis();
            int userid = (int) (Math.random() * 10000 + 1001);
            String orderNo = UUID.randomUUID().toString();
            Double totalAmount = 1000.00;
            orderMapper.save(id,userid,orderNo,totalAmount);
        }

    }

    public void createOrder(HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("账户记录", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 查询总条数
        int total = orderMapper.countAll();
        int pageSize = 250000;
        // 分多少页
        int pageTotal = (total % pageSize == 0 ? total / pageSize : total / pageSize + 1);
        log.info("导出数据总量：{}条，预计导出文件数量：{}件", total, pageTotal);

        ExecutorService executorService = Executors.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors() * 2));
        CountDownLatch countDownLatch = new CountDownLatch(pageTotal);
        long start = System.currentTimeMillis();

        // 单线程负责写入 Excel，防止并发冲突
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), Order.class).autoCloseStream(false).build();

        for (int i = 0; i < pageTotal; i++) {
            int startIndex = i * pageSize;
            String sheetName = "账户记录" + i;
            int sheetIndex = i;
            executorService.submit(() -> {
                try {
                    List<Order> orderList = orderMapper.getAllOrder2(startIndex);
                     // sheet number should be integer
                    WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, sheetName + "(" + startIndex + "-" + (startIndex + pageSize) + ")").build();

                    synchronized (excelWriter) {
                        excelWriter.write(orderList, writeSheet);
                    }

                    log.info("线程：{} 写入完成", Thread.currentThread().getName());
                } catch (Exception e) {
                    log.error("导出订单数据异常", e);
                    response.reset(); // 清空已写内容
                    try {
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "导出失败");
                    } catch (IOException ioEx) {
                        log.error("发送错误响应失败", ioEx);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
        }

        countDownLatch.await(); // 等待所有线程完成
        excelWriter.finish(); // 完成写入
        // 关闭资源：防止占用资源
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }

        long end = System.currentTimeMillis();
        log.info("数据导出完成，耗时：{}ms", end - start);
    }

}

